#include <stdio.h>
#include <sys/time.h>
#include <sched.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <error.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>          // 系统调用相关的函数 close()
#include <string.h>          // strcpy, memset(), and memcpy()
#include <sys/types.h>       // 包含了一些基本的系统数据类型 uint8_t、uint16_t 和 uint32_t
#include <sys/socket.h>      // 与套接字相关的函数和数据结构
#include <netinet/in.h>      // 与 Internet 协议族相关的数据结构
#include <netinet/ip.h>      // IP 协议头部的数据结构
#include <netinet/ip_icmp.h> // 定义了 ICMP 协议头部的数据结构
#include <arpa/inet.h>       // 定义了一些 IP 地址转换函数
#include <sys/ioctl.h>       // 进行输入/输出控制的函数和相关宏
#include <bits/ioctls.h>     // 用于 ioctl() 函数的参数
#include <net/if.h>          // 处理网络接口相关的函数和数据结构
#include <linux/if_ether.h>  // 帧格式 以太网帧的一些常量
#include <linux/if_packet.h> // 用于与套接字相关联的网络接口的数据结构 struct sockaddr_ll
#include <net/ethernet.h>    // 以太网帧的数据结构
#include <errno.h>           // errno, perror()
#include <iostream>

#include "tsmp.h"
#include "ptp.h"

// #define ETH_P_DEAN 0x8585 // 自定义的以太网协议 type
#define PACKET_LEN 2048 // 数据包的最大长度为 2048 字节
#define NET_INIT "enp7s0"

extern Port_delay port_delay;
extern Ptp_Sync ptp_sync;

uint8_t NEED_RESP = 0x01;
uint8_t NO_NEED_RESP = 0x00;
uint16_t global_sequence_id = 0x0;

void send_frame(int sig, siginfo_t *info, void *context) // 到时触发发送程序, sig判断类型，后续两个参数无用
{
    char *type;                     // 收到的类型
    uint8_t *ptp;                   // ptp报文
    int iRet;                       // 用来判断是否封装正确
    struct Resp_rec tsmp_resp_req;  //  = respRec(); //  接收 reqRec() req 的回应
    struct Resp_rec tsmp_resp_resp; // = respRec(); //  接收 respRec()
    uint64_t t1, t4;
    switch (sig)
    {
    case 10:
        type = "pdelayreq";
        global_sequence_id += 1;
        port_delay.sequence_id = global_sequence_id;

        printf("squence id is %x\n",port_delay.sequence_id);

        ptp = sendPdelayReq(global_sequence_id);
        iRet = packSend(ptp, NEED_RESP);
        if (iRet != 0)
        {
            perror("send error\n");
        }
        printf("message type is: %s\n\n", type);
        break;
    case 20:
        type = "pdelayresp";
        ptp = sendPdelayResp();
        iRet = packSend(ptp, NEED_RESP);
        if (iRet != 0)
        {
            perror("send error\n");
        }

        printf("message type: %s\n\n", type);
        break;
    case 30:
        type = "pdelayrespfollowup";
        ptp = sendPdelayRespFollowUp();
        iRet = packSend(ptp, NO_NEED_RESP);
        if (iRet != 0)
        {
            perror("send error\n");
        }
        printf("message type: %s\n\n", type);
        break;
    default:
        break;
    }
    return;
}

int packRec()
{
    struct Pack_rec tsmp_pack;
    uint64_t t0, t1, t4;
    int sd; // socket句柄
    // 创建套接字
    sd = create_socket_handle(NET_INIT);
    if (sd < 0)
    {
        printf("socket error\n");
    }

    char buf[PACKET_LEN]; // data
    int len, iRet;

    memset(buf, 0, sizeof(buf)); // 刷新缓冲
    struct Pack_rec *eth = (struct Pack_rec *)buf;
    // 将字符数组 buf 转换为了 struct s_ethernet_header 类型的指针 eth
    // 直接通过 eth 指针来访问以太网帧中的各个字段
    // 接收数据
    while (1)
    {
        len = recvfrom(sd, buf, PACKET_LEN, 0, NULL, NULL);

        if (ntohs(eth->head.ptcl_id) == 0xff01)
        {
            memcpy(&tsmp_pack.head, &eth->head, sizeof(Tsmp_rec_head));          // 打包头
            memcpy(&tsmp_pack.payload, &eth->payload, sizeof(Pack_rec_payload)); // 打包负载
            // printf("版本：%02x\n", tsmp_pack.head.version);                      // 用于测试
            // 判断接收到的帧是否是响应帧
            if (eth->head.type == 0x11)
            {
                printf("响应接收到了\n");
                t1 = ((uint64_t)ntohl(tsmp_pack.head.local_time_sec)) << 32 | ntohl(tsmp_pack.head.local_time_nanosec); // 获取本地时间
                port_delay.timestamp_1 = t1;
                // printf("t1=%lx\n", port_delay.timestamp_1);
            }
            else if (eth->head.type == 0x12)
            {
                struct Init_pack init_pack; // 取ptp
                memcpy(&init_pack, &tsmp_pack, sizeof(struct Init_pack));
                uint8_t type = init_pack.ptp_header.message_type;
                printf("type:%x\n", type);
                switch (type)
                {
                case PtpMsgType::E_PDELAY_RESP:
                    t4 = ((uint64_t)ntohl(tsmp_pack.head.local_time_sec)) << 32 | ntohl(tsmp_pack.head.local_time_nanosec);
                    port_delay.timestamp_4 = t4;
                    // printf("t4=%lx\n", port_delay.timestamp_4);
                    iRet = parsePdelayResp(tsmp_pack); // 接收pdelay_resp
                    if (iRet == -1)
                    {
                        std::cout << "parse pdelay resp error" << std::endl;
                    }
                    printf("resp接收到了\n");
                    break;
                case PtpMsgType::E_PDELAY_RESP_FOLLOW_UP:
                    iRet = parsePdelayRespFollowUp(tsmp_pack); // 接收pdelay_resp_follow_up
                    if (iRet == -1)
                    {
                        std::cout << "parse pdelay resp follow up error" << std::endl;
                    }
                    printf("resp follow up接收到了\n");
                    break;
                case PtpMsgType::E_SYNC:
                    t0 = ((uint64_t)ntohl(tsmp_pack.head.global_time_sec)) << 32 | ntohl(tsmp_pack.head.global_time_nanosec);
                    ptp_sync.t0 = t0;
                    iRet = parseSync(tsmp_pack);
                    if (iRet == -1)
                    {
                        std::cout << "parse sync error" << std::endl;
                    }
                    printf("sync接收到了\n");
                    break;
                case PtpMsgType::E_FOLLOW_UP:
                    iRet = parseFollowUp(tsmp_pack);
                    if (iRet == -1)
                    {
                        std::cout << "parse follow up error" << std::endl;
                    }
                    printf("follow up接收到了\n");
                    break;
                default:
                    break;
                }
            }
        }
    }

    close(sd);
    return 0;
}

// timer_fun函数实现定时器创建和初始化的一些列功能，参数seconds为定时周期，与pdelay相关的定时器
int timer_fun(int seconds)
{
    timer_t timerid;
    struct sigevent sev;
    struct itimerspec its;
    struct sigaction sa;

    // 注册信号处理函数
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = send_frame; // 指定了信号处理函数

    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGUSR1, &sa, NULL) == -1)
    {
        perror("sigaction");
        return -1;
    }

    // 创建定时器
    sev.sigev_notify = SIGEV_SIGNAL; // 到时间时发送信号
    sev.sigev_signo = SIGUSR1;
    sev.sigev_value.sival_ptr = &timerid;
    if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1)
    {
        perror("timer_create");
        return -1;
    }

    // 设置定时器的超时时间
    its.it_value.tv_sec = seconds; // seconds秒后触发
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 6; // 触发之后的时间间隔
    its.it_interval.tv_nsec = 0;
    if (timer_settime(timerid, 0, &its, NULL) == -1)
    {
        perror("timer_settime");
        return -1;
    }

    return 0;
}

int main()
{
    int role = 0; // GM=1, Slave=0
    if (role == 0)
    {
        uint32_t rale[1] = {htonl(0x00000001)};
        writeReqSend(0x40000000, 1, rale); // set slave_role_reg
    }
    // readReqSend(0x40000000, 1);
    //     uint32_t rale[1] = {htonl(0x08000004)};
    //     writeReqSend(0x00080000, 1, rale); // set slave_role_reg

    printf("----------------start------------------\n");
    timer_fun(2); //
    packRec();    // 打开receive

    return 0;
}
